library(tidyverse)
library(ggthemes)
library(gridExtra)
library(langcog) # for multi_boot_standard
  
theme_set(theme_few())
# langcog package is installed by running
# install.packages("devtools")
# devtools::install_github("langcog/langcog")
# make a base plots
# for flipped coordinate system with prop correct on x
p1 = ggplot() +
  geom_hline(yintercept = 1/3, lty = 2) +
  scale_y_continuous('Proportion Correct', limits = c(-0.05, 1.05)) +
  theme(axis.title.y = element_blank(), axis.ticks.y = element_blank())
p2 = p1 + theme(axis.text.y = element_blank())

Intro

These are some preliminary visualizations of the data.

phylo <- read_csv('../data/species_data.csv') %>% select(species, clade, phylo)
mp_data <- read.csv("../data/merged_data/01_manyprimates_pilot_merged_data_v2.csv", 
                    stringsAsFactors = F) %>%
  left_join(phylo, by = 'species') %>%
  mutate(species = reorder(species, phylo),
         clade = fct_relevel(clade, 'lemur', 'old_world_monkey', 'ape'),
         delay = factor(delay))

Overview by species

First an overview of the data, plotted by species and delay. Small, transparent dots represent aggregated data for each individual by delay. Open dots are the group mean for that delay. Error bars are 95% confidence intervals. Text labels are the sample size.

plot_individual <- mp_data %>% 
  group_by(phylo, clade, species, delay, subject_site) %>%
  summarise(correct = mean(correct),
            nr_trials = max(trial))
plot_group <- plot_individual %>%
   multi_boot_standard(col = "correct")
# get sample sizes (for use in plots)
ns = mp_data %>%
  group_by(clade, species) %>%
  mutate(n = n_distinct(subject_site)) %>%
  group_by(clade, species, site, n) %>%
  summarise(n_by_site = n_distinct(subject_site))
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = plot_individual, aes(size = nr_trials), width = .1, height = .015, alpha = .15) +
  geom_point(data = plot_group, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
  geom_linerange(data = plot_group, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
  geom_text(data = ns, aes(label = n), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(species ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_size_area(max_size = 3, breaks = c(12, 24, 36)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  coord_flip()

ggsave('../graphs/02_01_overview.png', width = 4, height = 4.5, scale = 2)

1536x1728

Overview by species across delays

p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = plot_individual, aes(size = nr_trials), width = .1, height = .015, alpha = .15) +
  geom_point(data = plot_group, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
  geom_linerange(data = plot_group, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
  geom_text(data = ns, aes(label = n), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(species ~ ., switch = "y") +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_size_area(max_size = 3, breaks = c(12, 24, 36)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  coord_flip()

### vertical plot 
ggplot() +
  geom_jitter(data = plot_individual, aes(x = condition, y = correct, col = condition, size = nr_trials), width = .3,height = .015, alpha = .15)+
  geom_pointrange(data = plot_group, aes(x = condition, y = mean, col = condition,ymin = ci_lower, ymax = ci_upper),size = 1)+
  geom_hline(yintercept = 1/3, lty=2)+
  labs(x="",y="Proportion Correct Choice")+
  facet_grid(. ~ species ,switch = "y") +
  theme_few() + 
  ylim(-0.05,1.05)+
  guides(alpha = F)+
  theme(axis.text.x=element_blank(),axis.ticks.x=element_blank())+
  scale_colour_solarized(name="delay")+
   theme(legend.position="bottom")+
  scale_size_continuous(breaks = c(12,24,36))
Error in FUN(X[[i]], ...) : object 'condition' not found

p1 + aes(x = fct_rev(species), y = correct, col = clade) +
  geom_jitter(data = plot_individual2, width = .1, height = .015, alpha = .15, size = 3) +
  geom_point(data = plot_group2, aes(y = mean), shape = 1, size = 3, stroke = 1.5) +
  geom_linerange(data = plot_group2, aes(y = NULL, ymin = ci_lower, ymax = ci_upper), lwd = 1.2) +
  geom_text(data = ns, aes(label = n), y = -.05, col = 'black', size = 3) +
  facet_grid(clade ~. , scales = 'free_y', space = 'free_y') +
  theme(strip.text.y = element_blank()) +  
  scale_colour_solarized() +
  coord_flip()

ggsave('../graphs/02_02_overview_across_delays.png', width = 4, height = 1.8, scale = 2)

Plots by site

Here we select the species for which we have data from multiple sites. This is a very preliminary way of checking whether there is a lot of variation between sites. Plotting conventions are the same as above.

First we check for which species we have data from more than one site:

mp_data %>%
  group_by(species) %>%
  summarise(sites = n_distinct(site)) %>%
  arrange(desc(sites)) %>%
  knitr::kable()
species sites
chimpanzee 5
ring_tailed_lemur 2
brown_capuchin_monkey 2
bonobo 2
gorilla 2
black_and_white_ruffed_lemur 1
black_faced_spider_monkey 1
squirrel_monkey 1
rhesus_macaque 1
long_tailed_macaque 1
barbary_macaque 1
orangutan 1

Chimpanzees

chimp_plot_individual <- mp_data %>%
  filter(species == "chimpanzee") %>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
chimp_plot_group <- chimp_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = chimp_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = chimp_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == 'chimpanzee'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(site ~ ., switch = 'y') +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  ggtitle("Chimpanzees") +
  coord_flip()

# ggsave('../graphs/02_03_chimp_by_site.png', width = 4, height = 2.5, scale = 2, type = 'cairo', compression = 'lzw')
ggsave('../graphs/02_03_chimp_by_site.png', width = 4, height = 2.5, scale = 2)

Ring-tailed lemurs

rtlemur_plot_individual <- mp_data %>%
  filter(species == "ring_tailed_lemur")%>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
rtlemur_plot_group <- rtlemur_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = rtlemur_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = rtlemur_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == 'ring_tailed_lemur'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(site ~ ., switch = 'y') +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  ggtitle("Ring-tailed lemurs") +
  coord_flip()

ggsave('../graphs/02_04_rtlemur_by_site.png', width = 4, height = 1.2, scale = 2)

Brown Capuchins

cap_plot_individual <- mp_data %>%
  filter(species == "brown_capuchin_monkey")%>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
cap_plot_group <- cap_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = cap_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = cap_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == 'brown_capuchin_monkey'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(site ~ ., switch = 'y') +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  ggtitle("Capuchin Monkeys") +
  coord_flip()

ggsave('../graphs/02_05_capuchin_by_site.png', width = 4, height = 1.2, scale = 2)

Bonobos

bon_plot_individual <- mp_data %>%
  filter(species == "bonobo")%>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
bon_plot_group <- bon_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = bon_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = bon_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == 'bonobo'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(site ~ ., switch = 'y') +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  ggtitle("Bonobos") +
  coord_flip()

ggsave('../graphs/02_06_bonobo_by_site.png', width = 4, height = 1.2, scale = 2)

Gorilla

gor_plot_individual <- mp_data %>%
  filter(species == "gorilla")%>%
  group_by(site, delay, subject_site) %>%
  summarise(correct = mean(correct))
gor_plot_group <- gor_plot_individual %>%
   multi_boot_standard(col = "correct")
p2 + aes(x = delay, y = correct, col = delay) +
  geom_jitter(data = gor_plot_individual, width = .1, height = .015, alpha = .3, size = 3) +
  geom_pointrange(data = gor_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper), size = .8, shape = 1, stroke = 1.5) +
  geom_text(data = filter(ns, species == 'gorilla'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(site ~ ., switch = 'y') +
  theme(strip.text.y = element_text(angle = 180)) +
  scale_colour_solarized(breaks = c('short', 'medium', 'long')) +
  ggtitle("Gorillas") +
  coord_flip()

ggsave('../graphs/02_07_gorilla_by_site.png', width = 4, height = 1.2, scale = 2)

Task-experience

Here we split each species by task experience. Check if we have species with sufficient memebers having different levels of task experience.

mp_data %>%
  group_by(species) %>%
  mutate(lvls_task_exp = n_distinct(task_experience)) %>%
  filter(lvls_task_exp > 1) %>%
  group_by(species, task_experience) %>%
  summarise(n = n_distinct(subject_site)) %>%
  knitr::kable()
species task_experience n
chimpanzee no 19
chimpanzee yes 32
bonobo no 6
bonobo yes 5
# get sample sizes (for use in plots)
ns_task_exp = mp_data %>%
  group_by(clade, species) %>%
  mutate(n = n_distinct(task_experience)) %>%
  group_by(clade, species, task_experience, n) %>%
  summarise(n_by_site = n_distinct(subject_site))

So far, this only applies to chimps and bonobos. However, task experience co-varies with site.

chimp_task_plot_individual <- mp_data %>%
  filter(species == "chimpanzee") %>%
  group_by(site, task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct))
chimp_task_plot_group <- mp_data %>%
  filter(species == "chimpanzee") %>%
  group_by(task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct)) %>%
  multi_boot_standard(col = "correct")
p_taskexp_chimp = p2 + aes(x = delay, y = correct) +
  geom_jitter(data = chimp_task_plot_individual, aes(col = site), width = .3, height = .015, alpha = .5, size = 3) +
  geom_pointrange(data = chimp_task_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper, shape = delay), size = .8, stroke = 1.5) +
  geom_text(data = filter(ns_task_exp, species == 'chimpanzee'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(task_experience ~ ., switch = 'y') +
  theme(legend.box = 'horizontal', strip.text.y = element_text(angle = 180)) +
  scale_shape_manual(values = c(1, 2, 5), breaks = c('short', 'medium', 'long')) +
  scale_colour_solarized() +
  ggtitle("Chimpanzees") +
  coord_flip()
bonobo_task_plot_individual <- mp_data %>%
  filter(species == "bonobo") %>%
  group_by(site, task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct))
bonobo_task_plot_group <- mp_data %>%
  filter(species == "bonobo") %>%
  group_by(task_experience, delay, subject_site) %>%
  summarise(correct = mean(correct)) %>%
  multi_boot_standard(col = "correct")
p_taskexp_bon = p2 + aes(x = delay, y = correct) +
  geom_jitter(data = bonobo_task_plot_individual, aes(col = site), width = .3, height = .015, alpha = .5, size = 3) +
  geom_pointrange(data = bonobo_task_plot_group, aes(y = mean, ymin = ci_lower, ymax = ci_upper, shape = delay), size = .8, stroke = 1.5) +
  geom_text(data = filter(ns_task_exp, species == 'bonobo'), aes(label = n_by_site), y = -.05, x = 2, col = 'black', size = 3) +
  facet_grid(task_experience ~ ., switch = 'y') +
  theme(legend.box = 'horizontal', strip.text.y = element_text(angle = 180)) +
  scale_shape_manual(values = c(1, 2, 5), breaks = c('short', 'medium', 'long')) +
  scale_colour_solarized() +
  ggtitle("Bonobos") +
  coord_flip()
grid.arrange(p_taskexp_chimp, p_taskexp_bon, ncol = 1)

grob = arrangeGrob(p_taskexp_chimp, p_taskexp_bon, ncol = 1)
ggsave('../graphs/02_08_task_experience.png', grob, width = 4, height = 3, scale = 2)

Age

Here we plot age against correct choice separate for each delay and species. Regression line is smoothed delayal mean.

plot_age <- mp_data %>%
  mutate(delay = fct_rev(delay)) %>%
  group_by(subject_site, norm_age, clade, species, delay) %>%
  summarise(correct = mean(correct))
ggplot(plot_age, aes(x = norm_age, y = correct))+
  geom_jitter(aes(fill = clade), width = .05, height = .05, alpha = .5, size = 2.5, shape = 21, stroke = 0) +
  geom_smooth(aes(col = delay), method = "loess", show.legend = F) +
  geom_vline(xintercept = 0, lty = 2) +
  geom_hline(yintercept = 1/3, lty = 2) +
  facet_grid( ~ delay ) +
  labs(x = "Normed Age (relative to species longevity)", y ="Proportion Correct") +
  scale_color_manual(values = rev(solarized_palette(3))) +
  ylim(c(-.05, 1.05))

ggsave('../graphs/02_09_age_by_delay.png', width = 4, height = 1.3, scale = 2)
ggplot(plot_age, aes(x = norm_age, y = correct))+
  geom_jitter(aes(fill = species), width = .05, height = .05, alpha = .5, size = 2.5, shape = 21, stroke = 0) +
  geom_smooth(aes(col = delay), method = "loess", show.legend = F) +
  geom_vline(xintercept = 0, lty = 2) +
  geom_hline(yintercept = 1/3, lty = 2) +
  facet_grid(delay ~ clade, scales = 'free_x') +
  labs(x = "Normed Age (relative to species longevity)", y = "Proportion Correct") +
  theme(legend.position = 'bottom') +
  scale_color_manual(values = rev(solarized_palette(3))) +
  ylim(c(-.05, 1.05))

ggsave('../graphs/02_10_age_by_delay_species.png', width = 4, height = 3.4, scale = 2)

Cup distance

(sig. effect in preliminary model)

plot_cup <- mp_data %>%
   group_by(subject_site, cup_distance, clade, species, delay) %>%
   summarise(correct = mean(correct))
cp = ggplot(plot_cup, aes(x = cup_distance, y = correct)) +
  geom_jitter(aes(col = clade), width = .5, height = .15, alpha = .5, size = 2) +
  geom_smooth(method = "loess") +
  labs(x = "Cup Distance in cm", y = "Proportion Correct") +
  geom_hline(yintercept = 1/3, lty = 2) +
  scale_color_solarized() +
  ylim(c(-.05, 1.05))
cp + theme(plot.margin = unit(c(.5, 5, .5, .5), 'cm'))

ggsave('../graphs/02_11_cup_distance.png', cp, width = 3, height = 2, scale = 2)
LS0tCnRpdGxlOiAiTWFueVByaW1hdGVzIHBsb3RzIgphdXRob3I6ICJNYW51ZWwgQm9obiIKZGF0ZTogIk9jdCAxMCAyMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY3NzOiBzdHlsZS5jc3MKICAgIHRoZW1lOiBwYXBlcgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGdyaWRFeHRyYSkKbGlicmFyeShsYW5nY29nKSAjIGZvciBtdWx0aV9ib290X3N0YW5kYXJkCiAgCnRoZW1lX3NldCh0aGVtZV9mZXcoKSkKCiMgbGFuZ2NvZyBwYWNrYWdlIGlzIGluc3RhbGxlZCBieSBydW5uaW5nCiMgaW5zdGFsbC5wYWNrYWdlcygiZGV2dG9vbHMiKQojIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigibGFuZ2NvZy9sYW5nY29nIikKYGBgCgpgYGB7cn0KIyBtYWtlIGEgYmFzZSBwbG90cwojIGZvciBmbGlwcGVkIGNvb3JkaW5hdGUgc3lzdGVtIHdpdGggcHJvcCBjb3JyZWN0IG9uIHgKcDEgPSBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMS8zLCBsdHkgPSAyKSArCiAgc2NhbGVfeV9jb250aW51b3VzKCdQcm9wb3J0aW9uIENvcnJlY3QnLCBsaW1pdHMgPSBjKC0wLjA1LCAxLjA1KSkgKwogIHRoZW1lKGF4aXMudGl0bGUueSA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpKQoKcDIgPSBwMSArIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpKQpgYGAKCiMgSW50cm8KClRoZXNlIGFyZSBzb21lIHByZWxpbWluYXJ5IHZpc3VhbGl6YXRpb25zIG9mIHRoZSBkYXRhLgoKYGBge3IgbG9hZGluZyBkYXRhLCBtZXNzYWdlPUZBTFNFfQpwaHlsbyA8LSByZWFkX2NzdignLi4vZGF0YS9zcGVjaWVzX2RhdGEuY3N2JykgJT4lIHNlbGVjdChzcGVjaWVzLCBjbGFkZSwgcGh5bG8pCm1wX2RhdGEgPC0gcmVhZC5jc3YoIi4uL2RhdGEvbWVyZ2VkX2RhdGEvMDFfbWFueXByaW1hdGVzX3BpbG90X21lcmdlZF9kYXRhX3YyLmNzdiIsIAogICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBGKSAlPiUKICBsZWZ0X2pvaW4ocGh5bG8sIGJ5ID0gJ3NwZWNpZXMnKSAlPiUKICBtdXRhdGUoc3BlY2llcyA9IHJlb3JkZXIoc3BlY2llcywgcGh5bG8pLAogICAgICAgICBjbGFkZSA9IGZjdF9yZWxldmVsKGNsYWRlLCAnbGVtdXInLCAnb2xkX3dvcmxkX21vbmtleScsICdhcGUnKSwKICAgICAgICAgZGVsYXkgPSBmYWN0b3IoZGVsYXkpKQpgYGAKCiMgT3ZlcnZpZXcgYnkgc3BlY2llcwoKRmlyc3QgYW4gb3ZlcnZpZXcgb2YgdGhlIGRhdGEsIHBsb3R0ZWQgYnkgc3BlY2llcyBhbmQgZGVsYXkuIFNtYWxsLCB0cmFuc3BhcmVudCBkb3RzIHJlcHJlc2VudCBhZ2dyZWdhdGVkIGRhdGEgZm9yIGVhY2ggaW5kaXZpZHVhbCBieSBkZWxheS4gT3BlbiBkb3RzIGFyZSB0aGUgZ3JvdXAgbWVhbiBmb3IgdGhhdCBkZWxheS4gRXJyb3IgYmFycyBhcmUgOTUlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzLiBUZXh0IGxhYmVscyBhcmUgdGhlIHNhbXBsZSBzaXplLgoKYGBge3Igb3ZlcnZpZXcgYnkgc3BlY2llcywgd2FybmluZz1GQUxTRX0KcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lIAogIGdyb3VwX2J5KHBoeWxvLCBjbGFkZSwgc3BlY2llcywgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpLAogICAgICAgICAgICBucl90cmlhbHMgPSBtYXgodHJpYWwpKQoKcGxvdF9ncm91cCA8LSBwbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyfQojIGdldCBzYW1wbGUgc2l6ZXMgKGZvciB1c2UgaW4gcGxvdHMpCm5zID0gbXBfZGF0YSAlPiUKICBncm91cF9ieShjbGFkZSwgc3BlY2llcykgJT4lCiAgbXV0YXRlKG4gPSBuX2Rpc3RpbmN0KHN1YmplY3Rfc2l0ZSkpICU+JQogIGdyb3VwX2J5KGNsYWRlLCBzcGVjaWVzLCBzaXRlLCBuKSAlPiUKICBzdW1tYXJpc2Uobl9ieV9zaXRlID0gbl9kaXN0aW5jdChzdWJqZWN0X3NpdGUpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00LjV9CnAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QsIGNvbCA9IGRlbGF5KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IHBsb3RfaW5kaXZpZHVhbCwgYWVzKHNpemUgPSBucl90cmlhbHMpLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4xNSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IHBsb3RfZ3JvdXAsIGFlcyh5ID0gbWVhbiksIHNoYXBlID0gMSwgc2l6ZSA9IDMsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fbGluZXJhbmdlKGRhdGEgPSBwbG90X2dyb3VwLCBhZXMoeSA9IE5VTEwsIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgbHdkID0gMS4yKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBucywgYWVzKGxhYmVsID0gbiksIHkgPSAtLjA1LCB4ID0gMiwgY29sID0gJ2JsYWNrJywgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKHNwZWNpZXMgfiAuLCBzd2l0Y2ggPSAieSIpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODApKSArCiAgc2NhbGVfc2l6ZV9hcmVhKG1heF9zaXplID0gMywgYnJlYWtzID0gYygxMiwgMjQsIDM2KSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygnc2hvcnQnLCAnbWVkaXVtJywgJ2xvbmcnKSkgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpnZ3NhdmUoJy4uL2dyYXBocy8wMl8wMV9vdmVydmlldy5wbmcnLCB3aWR0aCA9IDQsIGhlaWdodCA9IDQuNSwgc2NhbGUgPSAyKQpgYGAKCjE1MzZ4MTcyOAoKIyBPdmVydmlldyBieSBzcGVjaWVzIGFjcm9zcyBkZWxheXMKCmBgYHtyIG92ZXJ2aWV3IGJ5IHNwZWNpZXMgYWNyb3NzIGRlbGF5cywgd2FybmluZz1GQUxTRX0KcGxvdF9pbmRpdmlkdWFsMiA8LSBwbG90X2luZGl2aWR1YWwgJT4lCiAgZ3JvdXBfYnkoY2xhZGUsIHNwZWNpZXMsIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKcGxvdF9ncm91cDIgPC0gcGxvdF9pbmRpdmlkdWFsMiAlPiUKICAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuOH0KcDEgKyBhZXMoeCA9IGZjdF9yZXYoc3BlY2llcyksIHkgPSBjb3JyZWN0LCBjb2wgPSBjbGFkZSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBwbG90X2luZGl2aWR1YWwyLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4xNSwgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50KGRhdGEgPSBwbG90X2dyb3VwMiwgYWVzKHkgPSBtZWFuKSwgc2hhcGUgPSAxLCBzaXplID0gMywgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV9saW5lcmFuZ2UoZGF0YSA9IHBsb3RfZ3JvdXAyLCBhZXMoeSA9IE5VTEwsIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgbHdkID0gMS4yKSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBucywgYWVzKGxhYmVsID0gbiksIHkgPSAtLjA1LCBjb2wgPSAnYmxhY2snLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoY2xhZGUgfi4gLCBzY2FsZXMgPSAnZnJlZV95Jywgc3BhY2UgPSAnZnJlZV95JykgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSkgKyAgCiAgc2NhbGVfY29sb3VyX3NvbGFyaXplZCgpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCcuLi9ncmFwaHMvMDJfMDJfb3ZlcnZpZXdfYWNyb3NzX2RlbGF5cy5wbmcnLCB3aWR0aCA9IDQsIGhlaWdodCA9IDEuOCwgc2NhbGUgPSAyKQpgYGAKCiMgUGxvdHMgYnkgc2l0ZQoKSGVyZSB3ZSBzZWxlY3QgdGhlIHNwZWNpZXMgZm9yIHdoaWNoIHdlIGhhdmUgZGF0YSBmcm9tIG11bHRpcGxlIHNpdGVzLiBUaGlzIGlzIGEgdmVyeSBwcmVsaW1pbmFyeSB3YXkgb2YgY2hlY2tpbmcgd2hldGhlciB0aGVyZSBpcyBhIGxvdCBvZiB2YXJpYXRpb24gYmV0d2VlbiBzaXRlcy4gUGxvdHRpbmcgY29udmVudGlvbnMgYXJlIHRoZSBzYW1lIGFzIGFib3ZlLgoKRmlyc3Qgd2UgY2hlY2sgZm9yIHdoaWNoIHNwZWNpZXMgd2UgaGF2ZSBkYXRhIGZyb20gbW9yZSB0aGFuIG9uZSBzaXRlOgoKYGBge3IgcGxvdHMgYnkgc2l0ZSwgcmVzdWx0cz0nYXNpcyd9Cm1wX2RhdGEgJT4lCiAgZ3JvdXBfYnkoc3BlY2llcykgJT4lCiAgc3VtbWFyaXNlKHNpdGVzID0gbl9kaXN0aW5jdChzaXRlKSkgJT4lCiAgYXJyYW5nZShkZXNjKHNpdGVzKSkgJT4lCiAga25pdHI6OmthYmxlKCkKYGBgCgojIyBDaGltcGFuemVlcwoKYGBge3J9CmNoaW1wX3Bsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJjaGltcGFuemVlIikgJT4lCiAgZ3JvdXBfYnkoc2l0ZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKY2hpbXBfcGxvdF9ncm91cCA8LSBjaGltcF9wbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0yLjV9CnAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QsIGNvbCA9IGRlbGF5KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGNoaW1wX3Bsb3RfaW5kaXZpZHVhbCwgd2lkdGggPSAuMSwgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuMywgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YSA9IGNoaW1wX3Bsb3RfZ3JvdXAsIGFlcyh5ID0gbWVhbiwgeW1pbiA9IGNpX2xvd2VyLCB5bWF4ID0gY2lfdXBwZXIpLCBzaXplID0gLjgsIHNoYXBlID0gMSwgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIobnMsIHNwZWNpZXMgPT0gJ2NoaW1wYW56ZWUnKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAnYmxhY2snLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICd5JykgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoJ3Nob3J0JywgJ21lZGl1bScsICdsb25nJykpICsKICBnZ3RpdGxlKCJDaGltcGFuemVlcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KIyBnZ3NhdmUoJy4uL2dyYXBocy8wMl8wM19jaGltcF9ieV9zaXRlLnBuZycsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi41LCBzY2FsZSA9IDIsIHR5cGUgPSAnY2Fpcm8nLCBjb21wcmVzc2lvbiA9ICdsencnKQpnZ3NhdmUoJy4uL2dyYXBocy8wMl8wM19jaGltcF9ieV9zaXRlLnBuZycsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi41LCBzY2FsZSA9IDIpCmBgYAoKCiMjIFJpbmctdGFpbGVkIGxlbXVycwoKYGBge3J9CnJ0bGVtdXJfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gInJpbmdfdGFpbGVkX2xlbXVyIiklPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpydGxlbXVyX3Bsb3RfZ3JvdXAgPC0gcnRsZW11cl9wbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjJ9CnAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QsIGNvbCA9IGRlbGF5KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IHJ0bGVtdXJfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gcnRsZW11cl9wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyKSwgc2l6ZSA9IC44LCBzaGFwZSA9IDEsIHN0cm9rZSA9IDEuNSkgKwogIGdlb21fdGV4dChkYXRhID0gZmlsdGVyKG5zLCBzcGVjaWVzID09ICdyaW5nX3RhaWxlZF9sZW11cicpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICdibGFjaycsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZChzaXRlIH4gLiwgc3dpdGNoID0gJ3knKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygnc2hvcnQnLCAnbWVkaXVtJywgJ2xvbmcnKSkgKwogIGdndGl0bGUoIlJpbmctdGFpbGVkIGxlbXVycyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCcuLi9ncmFwaHMvMDJfMDRfcnRsZW11cl9ieV9zaXRlLnBuZycsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKCiMjIEJyb3duIENhcHVjaGlucwoKYGBge3J9CmNhcF9wbG90X2luZGl2aWR1YWwgPC0gbXBfZGF0YSAlPiUKICBmaWx0ZXIoc3BlY2llcyA9PSAiYnJvd25fY2FwdWNoaW5fbW9ua2V5IiklPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpjYXBfcGxvdF9ncm91cCA8LSBjYXBfcGxvdF9pbmRpdmlkdWFsICU+JQogICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwMiArIGFlcyh4ID0gZGVsYXksIHkgPSBjb3JyZWN0LCBjb2wgPSBkZWxheSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBjYXBfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gY2FwX3Bsb3RfZ3JvdXAsIGFlcyh5ID0gbWVhbiwgeW1pbiA9IGNpX2xvd2VyLCB5bWF4ID0gY2lfdXBwZXIpLCBzaXplID0gLjgsIHNoYXBlID0gMSwgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIobnMsIHNwZWNpZXMgPT0gJ2Jyb3duX2NhcHVjaGluX21vbmtleScpLCBhZXMobGFiZWwgPSBuX2J5X3NpdGUpLCB5ID0gLS4wNSwgeCA9IDIsIGNvbCA9ICdibGFjaycsIHNpemUgPSAzKSArCiAgZmFjZXRfZ3JpZChzaXRlIH4gLiwgc3dpdGNoID0gJ3knKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoYnJlYWtzID0gYygnc2hvcnQnLCAnbWVkaXVtJywgJ2xvbmcnKSkgKwogIGdndGl0bGUoIkNhcHVjaGluIE1vbmtleXMiKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKYGBge3J9Cmdnc2F2ZSgnLi4vZ3JhcGhzLzAyXzA1X2NhcHVjaGluX2J5X3NpdGUucG5nJywgd2lkdGggPSA0LCBoZWlnaHQgPSAxLjIsIHNjYWxlID0gMikKYGBgCgojIyBCb25vYm9zCgpgYGB7cn0KYm9uX3Bsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJib25vYm8iKSU+JQogIGdyb3VwX2J5KHNpdGUsIGRlbGF5LCBzdWJqZWN0X3NpdGUpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkKCmJvbl9wbG90X2dyb3VwIDwtIGJvbl9wbG90X2luZGl2aWR1YWwgJT4lCiAgIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjJ9CnAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QsIGNvbCA9IGRlbGF5KSArCiAgZ2VvbV9qaXR0ZXIoZGF0YSA9IGJvbl9wbG90X2luZGl2aWR1YWwsIHdpZHRoID0gLjEsIGhlaWdodCA9IC4wMTUsIGFscGhhID0gLjMsIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludHJhbmdlKGRhdGEgPSBib25fcGxvdF9ncm91cCwgYWVzKHkgPSBtZWFuLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciksIHNpemUgPSAuOCwgc2hhcGUgPSAxLCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihucywgc3BlY2llcyA9PSAnYm9ub2JvJyksIGFlcyhsYWJlbCA9IG5fYnlfc2l0ZSksIHkgPSAtLjA1LCB4ID0gMiwgY29sID0gJ2JsYWNrJywgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKHNpdGUgfiAuLCBzd2l0Y2ggPSAneScpICsKICB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGUgPSAxODApKSArCiAgc2NhbGVfY29sb3VyX3NvbGFyaXplZChicmVha3MgPSBjKCdzaG9ydCcsICdtZWRpdW0nLCAnbG9uZycpKSArCiAgZ2d0aXRsZSgiQm9ub2JvcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCcuLi9ncmFwaHMvMDJfMDZfYm9ub2JvX2J5X3NpdGUucG5nJywgd2lkdGggPSA0LCBoZWlnaHQgPSAxLjIsIHNjYWxlID0gMikKYGBgCgojIyBHb3JpbGxhCgpgYGB7cn0KZ29yX3Bsb3RfaW5kaXZpZHVhbCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJnb3JpbGxhIiklPiUKICBncm91cF9ieShzaXRlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCgpnb3JfcGxvdF9ncm91cCA8LSBnb3JfcGxvdF9pbmRpdmlkdWFsICU+JQogICBtdWx0aV9ib290X3N0YW5kYXJkKGNvbCA9ICJjb3JyZWN0IikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9MS4yfQpwMiArIGFlcyh4ID0gZGVsYXksIHkgPSBjb3JyZWN0LCBjb2wgPSBkZWxheSkgKwogIGdlb21faml0dGVyKGRhdGEgPSBnb3JfcGxvdF9pbmRpdmlkdWFsLCB3aWR0aCA9IC4xLCBoZWlnaHQgPSAuMDE1LCBhbHBoYSA9IC4zLCBzaXplID0gMykgKwogIGdlb21fcG9pbnRyYW5nZShkYXRhID0gZ29yX3Bsb3RfZ3JvdXAsIGFlcyh5ID0gbWVhbiwgeW1pbiA9IGNpX2xvd2VyLCB5bWF4ID0gY2lfdXBwZXIpLCBzaXplID0gLjgsIHNoYXBlID0gMSwgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIobnMsIHNwZWNpZXMgPT0gJ2dvcmlsbGEnKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAnYmxhY2snLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQoc2l0ZSB+IC4sIHN3aXRjaCA9ICd5JykgKwogIHRoZW1lKHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9jb2xvdXJfc29sYXJpemVkKGJyZWFrcyA9IGMoJ3Nob3J0JywgJ21lZGl1bScsICdsb25nJykpICsKICBnZ3RpdGxlKCJHb3JpbGxhcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7cn0KZ2dzYXZlKCcuLi9ncmFwaHMvMDJfMDdfZ29yaWxsYV9ieV9zaXRlLnBuZycsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMS4yLCBzY2FsZSA9IDIpCmBgYAoKIyBUYXNrLWV4cGVyaWVuY2UKCkhlcmUgd2Ugc3BsaXQgZWFjaCBzcGVjaWVzIGJ5IHRhc2sgZXhwZXJpZW5jZS4gQ2hlY2sgaWYgd2UgaGF2ZSBzcGVjaWVzIHdpdGggc3VmZmljaWVudCBtZW1lYmVycyBoYXZpbmcgZGlmZmVyZW50IGxldmVscyBvZiB0YXNrIGV4cGVyaWVuY2UuCgpgYGB7ciBwbG90cyBieSB0YXNrIGV4cGVyaWVuY2UsIHJlc3VsdHM9J2FzaXMnfQptcF9kYXRhICU+JQogIGdyb3VwX2J5KHNwZWNpZXMpICU+JQogIG11dGF0ZShsdmxzX3Rhc2tfZXhwID0gbl9kaXN0aW5jdCh0YXNrX2V4cGVyaWVuY2UpKSAlPiUKICBmaWx0ZXIobHZsc190YXNrX2V4cCA+IDEpICU+JQogIGdyb3VwX2J5KHNwZWNpZXMsIHRhc2tfZXhwZXJpZW5jZSkgJT4lCiAgc3VtbWFyaXNlKG4gPSBuX2Rpc3RpbmN0KHN1YmplY3Rfc2l0ZSkpICU+JQogIGtuaXRyOjprYWJsZSgpCmBgYAoKYGBge3J9CiMgZ2V0IHNhbXBsZSBzaXplcyAoZm9yIHVzZSBpbiBwbG90cykKbnNfdGFza19leHAgPSBtcF9kYXRhICU+JQogIGdyb3VwX2J5KGNsYWRlLCBzcGVjaWVzKSAlPiUKICBtdXRhdGUobiA9IG5fZGlzdGluY3QodGFza19leHBlcmllbmNlKSkgJT4lCiAgZ3JvdXBfYnkoY2xhZGUsIHNwZWNpZXMsIHRhc2tfZXhwZXJpZW5jZSwgbikgJT4lCiAgc3VtbWFyaXNlKG5fYnlfc2l0ZSA9IG5fZGlzdGluY3Qoc3ViamVjdF9zaXRlKSkKYGBgCgpTbyBmYXIsIHRoaXMgb25seSBhcHBsaWVzIHRvIGNoaW1wcyBhbmQgYm9ub2Jvcy4gSG93ZXZlciwgdGFzayBleHBlcmllbmNlIGNvLXZhcmllcyB3aXRoIHNpdGUuCgo8IS0tICMjIENoaW1wYW56ZWVzIC0tPgoKYGBge3J9CmNoaW1wX3Rhc2tfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gImNoaW1wYW56ZWUiKSAlPiUKICBncm91cF9ieShzaXRlLCB0YXNrX2V4cGVyaWVuY2UsIGRlbGF5LCBzdWJqZWN0X3NpdGUpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkKCmNoaW1wX3Rhc2tfcGxvdF9ncm91cCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJjaGltcGFuemVlIikgJT4lCiAgZ3JvdXBfYnkodGFza19leHBlcmllbmNlLCBkZWxheSwgc3ViamVjdF9zaXRlKSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpICU+JQogIG11bHRpX2Jvb3Rfc3RhbmRhcmQoY29sID0gImNvcnJlY3QiKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0xLjJ9CnBfdGFza2V4cF9jaGltcCA9IHAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QpICsKICBnZW9tX2ppdHRlcihkYXRhID0gY2hpbXBfdGFza19wbG90X2luZGl2aWR1YWwsIGFlcyhjb2wgPSBzaXRlKSwgd2lkdGggPSAuMywgaGVpZ2h0ID0gLjAxNSwgYWxwaGEgPSAuNSwgc2l6ZSA9IDMpICsKICBnZW9tX3BvaW50cmFuZ2UoZGF0YSA9IGNoaW1wX3Rhc2tfcGxvdF9ncm91cCwgYWVzKHkgPSBtZWFuLCB5bWluID0gY2lfbG93ZXIsIHltYXggPSBjaV91cHBlciwgc2hhcGUgPSBkZWxheSksIHNpemUgPSAuOCwgc3Ryb2tlID0gMS41KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBmaWx0ZXIobnNfdGFza19leHAsIHNwZWNpZXMgPT0gJ2NoaW1wYW56ZWUnKSwgYWVzKGxhYmVsID0gbl9ieV9zaXRlKSwgeSA9IC0uMDUsIHggPSAyLCBjb2wgPSAnYmxhY2snLCBzaXplID0gMykgKwogIGZhY2V0X2dyaWQodGFza19leHBlcmllbmNlIH4gLiwgc3dpdGNoID0gJ3knKSArCiAgdGhlbWUobGVnZW5kLmJveCA9ICdob3Jpem9udGFsJywgc3RyaXAudGV4dC55ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMTgwKSkgKwogIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXMgPSBjKDEsIDIsIDUpLCBicmVha3MgPSBjKCdzaG9ydCcsICdtZWRpdW0nLCAnbG9uZycpKSArCiAgc2NhbGVfY29sb3VyX3NvbGFyaXplZCgpICsKICBnZ3RpdGxlKCJDaGltcGFuemVlcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgo8IS0tICMjIEJvbm9ib3MgLS0+CgpgYGB7cn0KYm9ub2JvX3Rhc2tfcGxvdF9pbmRpdmlkdWFsIDwtIG1wX2RhdGEgJT4lCiAgZmlsdGVyKHNwZWNpZXMgPT0gImJvbm9ibyIpICU+JQogIGdyb3VwX2J5KHNpdGUsIHRhc2tfZXhwZXJpZW5jZSwgZGVsYXksIHN1YmplY3Rfc2l0ZSkgJT4lCiAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQoKYm9ub2JvX3Rhc2tfcGxvdF9ncm91cCA8LSBtcF9kYXRhICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJib25vYm8iKSAlPiUKICBncm91cF9ieSh0YXNrX2V4cGVyaWVuY2UsIGRlbGF5LCBzdWJqZWN0X3NpdGUpICU+JQogIHN1bW1hcmlzZShjb3JyZWN0ID0gbWVhbihjb3JyZWN0KSkgJT4lCiAgbXVsdGlfYm9vdF9zdGFuZGFyZChjb2wgPSAiY29ycmVjdCIpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuMn0KcF90YXNrZXhwX2JvbiA9IHAyICsgYWVzKHggPSBkZWxheSwgeSA9IGNvcnJlY3QpICsKICBnZW9tX2ppdHRlcihkYXRhID0gYm9ub2JvX3Rhc2tfcGxvdF9pbmRpdmlkdWFsLCBhZXMoY29sID0gc2l0ZSksIHdpZHRoID0gLjMsIGhlaWdodCA9IC4wMTUsIGFscGhhID0gLjUsIHNpemUgPSAzKSArCiAgZ2VvbV9wb2ludHJhbmdlKGRhdGEgPSBib25vYm9fdGFza19wbG90X2dyb3VwLCBhZXMoeSA9IG1lYW4sIHltaW4gPSBjaV9sb3dlciwgeW1heCA9IGNpX3VwcGVyLCBzaGFwZSA9IGRlbGF5KSwgc2l6ZSA9IC44LCBzdHJva2UgPSAxLjUpICsKICBnZW9tX3RleHQoZGF0YSA9IGZpbHRlcihuc190YXNrX2V4cCwgc3BlY2llcyA9PSAnYm9ub2JvJyksIGFlcyhsYWJlbCA9IG5fYnlfc2l0ZSksIHkgPSAtLjA1LCB4ID0gMiwgY29sID0gJ2JsYWNrJywgc2l6ZSA9IDMpICsKICBmYWNldF9ncmlkKHRhc2tfZXhwZXJpZW5jZSB+IC4sIHN3aXRjaCA9ICd5JykgKwogIHRoZW1lKGxlZ2VuZC5ib3ggPSAnaG9yaXpvbnRhbCcsIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDE4MCkpICsKICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzID0gYygxLCAyLCA1KSwgYnJlYWtzID0gYygnc2hvcnQnLCAnbWVkaXVtJywgJ2xvbmcnKSkgKwogIHNjYWxlX2NvbG91cl9zb2xhcml6ZWQoKSArCiAgZ2d0aXRsZSgiQm9ub2JvcyIpICsKICBjb29yZF9mbGlwKCkKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9M30KZ3JpZC5hcnJhbmdlKHBfdGFza2V4cF9jaGltcCwgcF90YXNrZXhwX2JvbiwgbmNvbCA9IDEpCmBgYAoKYGBge3J9Cmdyb2IgPSBhcnJhbmdlR3JvYihwX3Rhc2tleHBfY2hpbXAsIHBfdGFza2V4cF9ib24sIG5jb2wgPSAxKQpnZ3NhdmUoJy4uL2dyYXBocy8wMl8wOF90YXNrX2V4cGVyaWVuY2UucG5nJywgZ3JvYiwgd2lkdGggPSA0LCBoZWlnaHQgPSAzLCBzY2FsZSA9IDIpCmBgYAoKCiMgQWdlCgpIZXJlIHdlIHBsb3QgYWdlIGFnYWluc3QgY29ycmVjdCBjaG9pY2Ugc2VwYXJhdGUgZm9yIGVhY2ggZGVsYXkgYW5kIHNwZWNpZXMuIFJlZ3Jlc3Npb24gbGluZSBpcyBzbW9vdGhlZCBkZWxheWFsIG1lYW4uCgpgYGB7cn0KcGxvdF9hZ2UgPC0gbXBfZGF0YSAlPiUKICBtdXRhdGUoZGVsYXkgPSBmY3RfcmV2KGRlbGF5KSkgJT4lCiAgZ3JvdXBfYnkoc3ViamVjdF9zaXRlLCBub3JtX2FnZSwgY2xhZGUsIHNwZWNpZXMsIGRlbGF5KSAlPiUKICBzdW1tYXJpc2UoY29ycmVjdCA9IG1lYW4oY29ycmVjdCkpCmBgYAoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTEuM30KZ2dwbG90KHBsb3RfYWdlLCBhZXMoeCA9IG5vcm1fYWdlLCB5ID0gY29ycmVjdCkpKwogIGdlb21faml0dGVyKGFlcyhmaWxsID0gY2xhZGUpLCB3aWR0aCA9IC4wNSwgaGVpZ2h0ID0gLjA1LCBhbHBoYSA9IC41LCBzaXplID0gMi41LCBzaGFwZSA9IDIxLCBzdHJva2UgPSAwKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbCA9IGRlbGF5KSwgbWV0aG9kID0gImxvZXNzIiwgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEvMywgbHR5ID0gMikgKwogIGZhY2V0X2dyaWQoIH4gZGVsYXkgKSArCiAgbGFicyh4ID0gIk5vcm1lZCBBZ2UgKHJlbGF0aXZlIHRvIHNwZWNpZXMgbG9uZ2V2aXR5KSIsIHkgPSJQcm9wb3J0aW9uIENvcnJlY3QiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHJldihzb2xhcml6ZWRfcGFsZXR0ZSgzKSkpICsKICB5bGltKGMoLS4wNSwgMS4wNSkpCmBgYAoKYGBge3J9Cmdnc2F2ZSgnLi4vZ3JhcGhzLzAyXzA5X2FnZV9ieV9kZWxheS5wbmcnLCB3aWR0aCA9IDQsIGhlaWdodCA9IDEuMywgc2NhbGUgPSAyKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zLjR9CmdncGxvdChwbG90X2FnZSwgYWVzKHggPSBub3JtX2FnZSwgeSA9IGNvcnJlY3QpKSsKICBnZW9tX2ppdHRlcihhZXMoZmlsbCA9IHNwZWNpZXMpLCB3aWR0aCA9IC4wNSwgaGVpZ2h0ID0gLjA1LCBhbHBoYSA9IC41LCBzaXplID0gMi41LCBzaGFwZSA9IDIxLCBzdHJva2UgPSAwKSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbCA9IGRlbGF5KSwgbWV0aG9kID0gImxvZXNzIiwgc2hvdy5sZWdlbmQgPSBGKSArCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gMCwgbHR5ID0gMikgKwogIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDEvMywgbHR5ID0gMikgKwogIGZhY2V0X2dyaWQoZGVsYXkgfiBjbGFkZSwgc2NhbGVzID0gJ2ZyZWVfeCcpICsKICBsYWJzKHggPSAiTm9ybWVkIEFnZSAocmVsYXRpdmUgdG8gc3BlY2llcyBsb25nZXZpdHkpIiwgeSA9ICJQcm9wb3J0aW9uIENvcnJlY3QiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gJ2JvdHRvbScpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcmV2KHNvbGFyaXplZF9wYWxldHRlKDMpKSkgKwogIHlsaW0oYygtLjA1LCAxLjA1KSkKYGBgCgpgYGB7cn0KZ2dzYXZlKCcuLi9ncmFwaHMvMDJfMTBfYWdlX2J5X2RlbGF5X3NwZWNpZXMucG5nJywgd2lkdGggPSA0LCBoZWlnaHQgPSAzLjQsIHNjYWxlID0gMikKYGBgCgoKIyBDdXAgZGlzdGFuY2UKCihzaWcuIGVmZmVjdCBpbiBwcmVsaW1pbmFyeSBtb2RlbCkKCmBgYHtyfQpwbG90X2N1cCA8LSBtcF9kYXRhICU+JQogICBncm91cF9ieShzdWJqZWN0X3NpdGUsIGN1cF9kaXN0YW5jZSwgY2xhZGUsIHNwZWNpZXMsIGRlbGF5KSAlPiUKICAgc3VtbWFyaXNlKGNvcnJlY3QgPSBtZWFuKGNvcnJlY3QpKQpgYGAKCmBgYHtyIHBsb3R0aW5nIGN1cCBkaXN0YW5jZSwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9Mn0KY3AgPSBnZ3Bsb3QocGxvdF9jdXAsIGFlcyh4ID0gY3VwX2Rpc3RhbmNlLCB5ID0gY29ycmVjdCkpICsKICBnZW9tX2ppdHRlcihhZXMoY29sID0gY2xhZGUpLCB3aWR0aCA9IC41LCBoZWlnaHQgPSAuMTUsIGFscGhhID0gLjUsIHNpemUgPSAyKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxvZXNzIikgKwogIGxhYnMoeCA9ICJDdXAgRGlzdGFuY2UgaW4gY20iLCB5ID0gIlByb3BvcnRpb24gQ29ycmVjdCIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAxLzMsIGx0eSA9IDIpICsKICBzY2FsZV9jb2xvcl9zb2xhcml6ZWQoKSArCiAgeWxpbShjKC0uMDUsIDEuMDUpKQoKY3AgKyB0aGVtZShwbG90Lm1hcmdpbiA9IHVuaXQoYyguNSwgNSwgLjUsIC41KSwgJ2NtJykpCmBgYAoKYGBge3J9Cmdnc2F2ZSgnLi4vZ3JhcGhzLzAyXzExX2N1cF9kaXN0YW5jZS5wbmcnLCBjcCwgd2lkdGggPSAzLCBoZWlnaHQgPSAyLCBzY2FsZSA9IDIpCmBgYAoK